#include "Member.h"
#include "Hotel.h"
#include "Review.h"
#include <string>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <termios.h>
#include <unistd.h>
#include <vector>
#include <iterator>

string encrypt(string, int);
string currentUser;
vector <Hotel> hotelVec;
vector <Member> memVec;
vector <Review> revVec;

void adminMenu();
void adminSubMenu();
void memberMenu();
void user_login();
void add_Hotel();


vector<string> &split(string &s,char d,vector <string> &v)
{
    stringstream ss(s);
    string token;
    
    while(getline(ss,token,d))
    {
        v.push_back(token);
    }
    
    return v;
}

void user_login()
{
    string user ="";
    string pwd = "";
    
    cout << "Enter user name:\n";
    cin >> user;    
    //hiding user input for password
    termios oldt;
    tcgetattr(STDIN_FILENO, &oldt);
    termios newt = oldt;
    newt.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    cout << "Enter password:\n";
    cin >> pwd;
    //clean up restore back to normal inputs
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    
    string epwd = encrypt(pwd, 5);
    Member m1;
    m1.setUID(user);
    m1.setUPW(epwd);
    
    string role = m1.member_login();
        
    if (role == "admin") {        
        adminMenu();        
    } else if( role == "member") {
	currentUser = user;        
        memberMenu();
    } else if( role == "wrong") {     
        cout << "Invalid user and password\n";               
    }
}

bool checkPermission(string permInput)
{
    bool retPerm;
    if(permInput == "1")
    {
	retPerm = 1;
    }
    else if(permInput == "0")
    {
	retPerm = 0;
    }
    return retPerm;
}

void readMemDB()
{
    string s;
    vector <string> strMem;
    Member m;
    int lockStatus;
    bool perm;

    ifstream inFile;
    inFile.open("members.txt");

    while(getline(inFile,s))
    {
        strMem = split(s,':',strMem);
	perm = checkPermission(strMem[3]);
	m = Member(strMem[0],strMem[1],strMem[2],perm);
        memVec.push_back(m);
	strMem.clear();
    }
}

void regMemberMenu()
{   
    string user, pwd, pwd2;
    bool correct = true;
    cout << "Enter username" << endl;
    cin >> user;
    while (correct != false){
        cout << "Enter password" << endl;
        cin >> pwd;
        cout << "Enter password again" << endl;
        cin >> pwd2;
        if (pwd == pwd2){
            correct = false;
        } else {
            cout << "Password do not match" << endl;
        }
    }
    string epwd = encrypt(pwd, 5);
    Member m1;
    m1.setUID(user);
    m1.setUPW(epwd);
    
    bool success = m1.reg_member();
    
    if (success == false){
        cout << "Member already existed, please try again." << endl;
    } else if (success == true){
        cout << "Registration successful\n" << endl;    
    }
    adminSubMenu();  
}

void removeMember()
{
    int i = 0;
    int j = 1;
    int num = 0;
    int temp;

    for(i = 0, j = 1; i < memVec.size(); i++, j++)
    {
	if(!memVec.empty())
	{
	    cout << j << ":" << memVec[i].getUID() << ":" << memVec[i].getUPW() << ":" << memVec[i].getRole() << ":" << memVec[i].getPerm() << endl; 
	}
    }

    cout << "Enter no. to remove member: ";
    cin >> num;
    while(num > hotelVec.size())
    {
	cout << "invalid number! enter no. to edit hotel: ";
	cin.clear();
	cin >> num;
    }

    temp = num-1;

    memVec.erase(memVec.begin() + temp);

    cout << "Member removed!" << endl << endl;
    adminSubMenu();
}

void editMember()
{
    memVec.clear();
    readMemDB();
    string uid = "";
    string pwd = "";
    string role = "";
    string strPerm = "";
    bool perm = 0;
    string line;
    int i = 0;
    int j = 1;
    int num = 0;
    vector <string> str;
    vector <string> temp;
    Member mem;

    cout << "No.:User ID:Password:Role:Permission" << endl;

    for (i = 0,j = 1 ; i < memVec.size(); i++, j++)
    {
	cout << j << " : " << memVec[i].getUID() << " : " << memVec[i].getRole() << " : " << memVec[i].getPerm() << endl << endl; 
    }

    cout << "Enter no. to edit Member: ";
    cin >> num;
    while(num > memVec.size())
    {
	cout << "Invalid number! enter no. to edit member: ";
	cin.clear();
	cin >> num;
    }
    
    cin.ignore();

    cout << "Enter new User ID: ";
    getline(cin,uid);
    cin.clear();

    cout << "Enter new password: ";
    getline(cin,pwd);
    cin.clear();
    string ciphered = encrypt(pwd,5);
	
    cout << "Enter new permission for posting a review (0 for false/1 for true): ";
    getline(cin,strPerm);
    cin.clear();

    perm = checkPermission(strPerm);

    mem = Member(uid,ciphered,"member",perm);

    int num2 = num-1;

    memVec[num2] = mem;

    cout << "Member edited! Returning to main menu..." << endl << endl;
    adminSubMenu();
}

void viewMember()
{
    int i = 0;
    int j = 1;
    cout << "No.:User ID:Role:Permission" << endl;
    for(i = 0, j = 1; i< memVec.size(); i++, j++)
    {
	cout << j << " : " << memVec[i].getUID() << " : " << memVec[i].getRole() << " : " << memVec[i].getPerm() << endl << endl; 
    }

    adminSubMenu();
}

void readDB()
{
    string s;
    vector <string> st;
    Hotel h;

    ifstream inFile;
    inFile.open("Hotel.txt");

    while(getline(inFile,s))
    {	
        st = split(s,':',st);
	h = Hotel(st[0],st[1]);
        hotelVec.push_back(h);
	st.clear();
    }

    inFile.close();
}

void add_Hotel()
{
    int i = 0;
    string name = "";
    string addr = "";

    cin.ignore();
    cout << "Enter hotel name: ";
    getline(cin,name);
    cin.clear();

    cout << "Enter hotel address: ";
    getline(cin,addr);
    cin.clear();

    Hotel h = Hotel(name,addr);

    for(i=0;i<hotelVec.size();i++)
    {
        if(hotelVec[i].getAddress() == h.getAddress())
        {
            cout << "Hotel address already exist, please enter anoter address: ";
            getline(cin,addr);
	    cin.clear();

	    h.setAddress(addr);
	}
    }

    hotelVec.push_back(h);
    
    cout << "Hotel has been added, returning to main menu..." << endl << endl;
    adminMenu();
}

void edit_Hotel()
{
    hotelVec.clear();
    string name = "";
    string addr = "";
    string line;
    int i = 0;
    int num = 0;
    int error = 0;
    vector <string> str;
    vector <string> temp;
    Hotel h(name,addr);

    readDB();
    cout << "No.:Hotel Name:Address" << endl;

    for(i = 0; i < hotelVec.size(); i++)
    {
	int j = i+1;
	cout << j << ":" << hotelVec[i].getHotelName() << ":" << hotelVec[i].getAddress() << endl; 
    }

    cout << "Enter no. to edit hotel: ";
    cin >> num;
    while(num > hotelVec.size())
    {
	cout << "Invalid number! enter no. to edit hotel: ";
	cin.clear();
	cin >> num;
    }

    cout << "Enter new hotel name: ";
    cin.ignore();
    getline(cin,name);
    cin.clear();

    cout << "Enter new address: ";
    getline(cin,addr);
    cin.clear();

    cout << name << addr;

    num = num - 1;

    h = Hotel(name,addr);

    hotelVec[num] = h;

    cout << "Hotel edited! Returning to main menu..." << endl << endl;
    adminMenu();
}

void remove_Hotel()
{
    int i = 0;
    int j = 1;
    int num = 0;
    int temp;

    for(i = 0, j = 1; i < hotelVec.size(); i++, j++)
    {
	if(!hotelVec.empty())
	{
	    cout << j << hotelVec[i].getHotelName() << ":" << hotelVec[i].getAddress() << endl; 
	}
    }

    cout << "Enter no. to remove hotel: ";
    cin >> num;
    while(num > hotelVec.size())
    {
	cout << "Invalid number! enter no. to remove hotel: ";
	cin.clear();
	cin >> num;
    }
    temp = num-1;

    hotelVec.erase(hotelVec.begin() + temp);

    cout << "Hotel removed successfully!" << endl << endl;
    adminMenu();
}

void updateDB()
{
    int i = 0;
    string temp,temp2;

    if(hotelVec.empty())
    {
	
    }

    else
    {
	ofstream outFile;
	outFile.open("Hotel.txt",ios::out);

	for(i = 0; i < hotelVec.size(); i++)
	{
	    temp = hotelVec[i].getHotelName() + ":" + hotelVec[i].getAddress();

	    outFile << temp << endl;
        }

	outFile.close();

	cout << "Hotel DB has been updated!" << endl << endl;
	adminMenu();
    }
}

void updateMemDB()
{
    int i = 0;
    string temp,temp2;
    if(memVec.empty())
    {
	
    }

    else
    {
	ofstream outFile;
	outFile.open("members.txt", ios::out);

	for(i = 0; i < memVec.size(); i++)
	{
	    if(memVec[i].getPerm() == true)
	    {
		temp2 = "1";
	    }

	    else if(memVec[i].getPerm() == false)
	    {
		temp2 = "0";
	    }
	
	    temp = memVec[i].getUID() + ":" + memVec[i].getUPW() + ":" + memVec[i].getRole() + ":" + temp2;

	    outFile << temp << endl;
	}
	outFile.close();
	cout << "Member DB has been updated!" << endl << endl;
	adminSubMenu();
    }
}

void readReviewsDB()
{
    ifstream infile;
	infile.open ("Reviews.txt");
	
	if (!infile)
	{
		cout << "Reviews.txt opened for reading failed" << endl;
		exit (-1);
	}	 
	
	string s;
	vector <string> st;
	Review r;
	
	while (getline (infile, s))
	{
		st = split (s, ':', st);
		int star = atoi (st[4].c_str());
		r = Review (st[0],st[1],st[2],st[3],star);
		
		revVec.push_back (r);
		st.clear ();
	}
	
	infile.close ();
}

void viewReviews ()
{
	Review r;
	vector <Review>::iterator ptr;
	ptr = revVec.begin ();

	cout << endl;
	cout << "\tCurrent Reviews" << endl;
	cout << endl;

	while (ptr != revVec.end ())
	{
		r = *ptr;
		cout << "Member Name (Reviewer): " << r.getUserID() << endl;
		cout << "Hotel Name: " << r.getHotelName () << endl;
    		cout << "Hotel Address: " << r.getHotelAddress () << endl;
     		cout << "Comments: " << r.getComment() << endl;
    		cout << "Stars: " << r.getStars () << endl;
		cout << endl;
			 
		ptr++;
	}
}

void postReview ()
{
	cout << endl;
	cout << "\tPost a Review" << endl;
	cout << endl;
	
	string hotelName, hotelAddress, comments;
	int stars;

	cout << "Hotel Name: ";
	cin.clear ();
	cin.ignore ();
	getline (cin, hotelName);

	cout << "Hotel Address: ";
	cin.clear ();
	getline (cin, hotelAddress);

	cout << "Please Enter your Comments: ";
	cin.clear ();
	getline (cin, comments);
	
	do
	{		
		cout << "Please rate your experience at the hotel on a scale of 1 to 10: ";
		cin >> stars;
	}while (stars > 10 || stars < 0);
	

	Review r (currentUser, hotelName, hotelAddress, comments, stars);
	revVec.push_back (r);

	fstream afile;
	afile.open ("Reviews.txt", ios::out);

	if (!afile)
	{
		cout << "Reviews.txt couldn't be opened for reading" << endl;
		exit (-1);
	}

	vector <Review>::iterator ptr;
	ptr = revVec.begin ();

	while (ptr != revVec.end ())
	{
		r = *ptr;
		afile << r.getUserID() << ":"
		      << r.getHotelName () << ":"
    		      << r.getHotelAddress () << ":"
     		      << r.getComment() << ":"
    		      << r.getStars() << endl;
		ptr++;
	}
	afile.close ();
	cout << "Review has been successfully posted!" << endl;
	cout << endl;
	//cout << currentUser << " " << hotelName <<  " " << hotelAddress << " " << comments << " " << stars << endl;	
}

void memberMenu()
{
    cin.ignore();
    int opt;    
    int i = 0;
    int j = 1;

    readDB();
    readReviewsDB ();

    do
    {
    cout << "Welcome members\n"
            "1) View hotels\n"
            "2) View Reviews\n"
            "3) Post a review\n"
            "4) Quit" << endl;
    cout << "Enter your option: ";
    cin >> opt;
    cout << endl;
    switch(opt)
    {
        case 1:
	    cout << "No.:Hotel name:Address" << endl;
            for(i = 0,j = 1; i < hotelVec.size(); i++, j++)
	    {
		cout << j << ":" << hotelVec[i].getHotelName() << ":" << hotelVec[i].getAddress() << endl;
	    }
	    hotelVec.clear();
	    memberMenu();
            break;
        case 2: 
		viewReviews ();            
            break;
        case 3: 
            	postReview ();
            break;
        case 4: 
            cout << "Thank you for using, good bye" << endl;
            break;        
        default : 
            cout << "Invalid option please try again" << endl; 
    }
    }while (opt != 4);
}

void adminSubMenu()
{
    if(memVec.empty())
    {
        readMemDB();
    }

    int opt;    
    cout << "Handling members\n"
            "1) Add new members\n"
            "2) Modify members permission\n"
            "3) Delete a member\n"
            "4) View members\n"
            "5) Back to main menu\n"
	    "6) Update member DB\n"
            "7) Quit" << endl;
    cin >> opt;
    switch(opt)
    {
        case 1:
            regMemberMenu();
            break;
        case 2: 
            editMember();
            break;
        case 3: 
            removeMember();
            break;
        case 4: 
            viewMember();
            break;
        case 5: 
            adminMenu();
            break;
	case 6:
	    updateMemDB();
	    break;
        case 7: 
            cout << "Thank you for using, good bye" << endl;    
            break;
        default : 
            cout << "Invalid option please try again" << endl; 
    }
}

void adminMenu()
{
    int opt;

    if(hotelVec.empty())
    {
	readDB();
    }

    cout << "Welcome administrator\n"
            "1) Add new hotel\n"
            "2) Modify hotel details\n"
            "3) Delete a hotel\n"
            "4) Handle members\n"
	    "5) Update hotel DB\n"
            "6) Quit" << endl;
    cin >> opt;
    switch(opt)
    {
        case 1:
            add_Hotel();
            break;
        case 2: 
            edit_Hotel();
            break;
        case 3:
	    remove_Hotel();
            break;
        case 4: 
            adminSubMenu();
            break;
	case 5:
	    updateDB();
	    break;
        case 6: 
            cout << "Thank you for using, good bye" << endl;    
            break;
        default : 
            cout << "Invalid option please try again" << endl; 
    }
}

string encrypt(string p, int Key)
{
    string Crypted = p;

    for(int Current = 0; Current < p.length(); Current++)
        Crypted[Current] += Key; //shift plaintext
    
    p = Crypted; 

    return p;
}

int main(){
    
    char choice[2];
    //std::regex rx("([a-z]|[A-Z])+");
    bool open = true;
    while (open != false){
        cout << "1. Login" << endl;        
        cout << "2. Exit" << endl;
        cin >> choice;
        
        if (choice[0] == '1'){
            user_login();
        } else if (choice[0] == '2') {
            cout << "Thank you good bye" << endl;
            open = false;
        } else if (choice[0] > '2' || choice[0] < '1'){
            cout << "Please enter valid choice \n" << endl;
        }
    
    }
}
